| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960 |
- 'use client';
- import { useEffect, useState } from 'react';
- import './youtube-chat-iframe.scss';
- type Props = {
- videoId: string|null;
- };
- /**
- * YouTube Live Chat 임베드 컴포넌트.
- *
- * - URL 형식: https://www.youtube.com/live_chat?v={VIDEO_ID}&embed_domain={HOST}
- * - embed_domain 은 NEXT_PUBLIC_EMBED_DOMAIN 환경변수 사용 (호스트만, 프로토콜/포트 제외)
- * - 라이브 중일 때만 정상 표시 (videoId 가 있어야 함)
- * - 비라이브 또는 환경변수 미설정 시 fallback UI
- *
- * Quota 비용: 0 — YouTube 자체 인프라 사용, antooza 의 quota 소비 없음.
- */
- export default function YouTubeChatIframe({ videoId }: Props)
- {
- const [embedDomain, setEmbedDomain] = useState<string|null>(null);
- useEffect(() => {
- // SSR 시점에는 process.env 가 없을 수 있어 마운트 후 해석
- const envDomain = process.env.NEXT_PUBLIC_EMBED_DOMAIN;
- if (envDomain) {
- setEmbedDomain(envDomain);
- return;
- }
- // fallback: 현재 호스트 (개발 환경 보조)
- if (typeof window !== 'undefined') {
- setEmbedDomain(window.location.hostname);
- }
- }, []);
- const chatUrl = videoId && embedDomain
- ? `https://www.youtube.com/live_chat?v=${encodeURIComponent(videoId)}&embed_domain=${encodeURIComponent(embedDomain)}`
- : null;
- return (
- <div className="yt-chat">
- {chatUrl ? (
- <iframe
- className="yt-chat__iframe"
- src={chatUrl}
- title="YouTube Live Chat"
- allow="autoplay"
- sandbox="allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox allow-forms"
- />
- ) : (
- <div className="yt-chat__offline">
- <p className="yt-chat__offline-title">현재 라이브 방송이 아닙니다</p>
- <p className="yt-chat__offline-desc">라이브 방송이 시작되면 채팅에 참여할 수 있어요.</p>
- </div>
- )}
- </div>
- );
- }
|